import {messages,decodeUtf8} from "share/common";
import React from 'react';
import { connect } from 'react-redux'
import {Modal, Button, Tabs, Upload, Icon, message, Table, Alert} from 'antd'
import httpFetch from 'share/httpFetch'
import FileSaver from 'file-saver'
import FileUpload from "components/template/ie-file-upload/file-upload";
import errorMessage from 'share/errorMessage';
import config from 'config'


//数据导入组件
class UploadTemplate extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      fileList: [],
      downloadingList: {}
    };
    this.uploadable = true;
    this.counter = 0;
  }

  componentWillMount() {
    this.uploadOptions = Object.assign({}, UploadTemplate.defaultProps.uploadOptions, this.props.uploadOptions);
  }

  componentWillReceiveProps(nextProps) {
    this.uploadOptions = Object.assign({}, UploadTemplate.defaultProps.uploadOptions, nextProps.uploadOptions);
    this.setState({ fileList: nextProps.fileList });
  }

  componentDidMount() {
    const { onRef } = this.props;
    onRef && (onRef(this));
  }

  componentWillUnMount() {
    this._clearTimeout();
  }

  _clearTimeout = () => this.delayer && clearTimeout(this.delayer);

  getErrorData = data => {
    const { errorTableData } = this.props;
    let errorData = [];
    if(typeof errorTableData === 'string') {
      errorData = data[errorTableData]
    } else if(typeof errorTableData === 'function') {
      errorData = errorTableData(data);
    } else {
      data.error && data.error.map(item => {
        Object.keys(item).map(key => {
          errorData.push({
            error: key,
            index: item[key].join()
          })
        })
      });
    }
    errorData && Array.isArray(errorData) && errorData.sort((a, b) => a.index - b.index);
    return errorData;
  };

  getTotal = data => {
    const { totalError } = this.props;
    let total = 0;
    if(typeof totalError === 'string') {
      total = data[totalError];
    } else if( typeof totalError === 'function' ) {
      total = totalError(data);
    } else {
      total = totalError;
    }
    return total;
  };

  getUploadResult = data => {
    const { parseUploadResult } = this.uploadOptions;
    if(parseUploadResult) {
      return parseUploadResult(data);
    } else {
      return {
        successEntities: data.successEntity || data.successEntities || data.successNum,
        failureEntities: data.failEntity || data.failureEntities || data.failNum
      }
    }
  };

  onUpload = () => {
    const { fileList } = this.state;
    const { onChange, onConfirmUpload, onValidate, asyncMode } = this.props;
    const { uploadParams, uploadUrl } = this.uploadOptions;
    if(!fileList || fileList.length === 0) {
      message.error(messages('common-1.key383')/*请选择文件后，再导入*/);
      return false;
    }
    if(onValidate && !onValidate(fileList)) {
      return false;
    }

    let isTransitionOid = oid => {
      if(typeof oid === 'string' && /[a-zA-Z0-9]{8}-([a-zA-Z0-9]{4}-){3}[a-zA-Z0-9]{12}/.test(oid)) {
        return oid;
      }
      return false;
    };

    const formData = new FormData();
    fileList.forEach((file) => formData.append('file', file));
    uploadParams && Object.keys(uploadParams).map(key => formData.append(key, uploadParams[key]));
    //第一次不需要initFlag参数
    onChange(asyncMode ? { tabKey: 'RESULT' } : { uploading: true });
    httpFetch.post(uploadUrl, formData, {"Content-type": 'multipart/form-data'}).then(res => {
      let transactionOID = res.data.transactionID || res.data.transactionOID || res.data.transactionUUID ||
        isTransitionOid(res.data) || null;
      if(!transactionOID && !asyncMode) {
        onChange({
          tabKey: 'RESULT',
          fileList: [],
          uploading: false,
          errorData: this.getErrorData(res.data),
          total: this.getTotal(res.data),
          uploadResult: this.getUploadResult(res.data)
        });
      } else if(transactionOID) {
        onChange({ transactionOID, importResponse: res.data });
        this.listenStatus(transactionOID);
      }
    }).catch(e => {
      console.log(e);
      onChange({ uploading: false });
      //是否需要二次确认
      onConfirmUpload && onConfirmUpload( e.response, this.onUpload );
      !onConfirmUpload && errorMessage(e.response, messages('common-1.key384')/*导入失败，请重试*/);
    })
  };

  //监听导入状态：PARSING_FILE(1001), PROCESS_DATA(1002), DONE(1003), ERROR(1004), CANCELLED(1005)
  listenStatus = transactionOID => {
    const { onChange, page } = this.props;
    const { listenUrl, queryMode } = this.uploadOptions;
    httpFetch.get(`${listenUrl}${queryMode ? `?transactionOID=${transactionOID}` : `/${transactionOID}`}`, {page, size: 10}).then(res => {
      if (res.data.status === 1004) {
        onChange({
          tabKey: 'RESULT',
          uploading: false,
          uploadResult: this.getUploadResult(res.data),
          errorData: this.getErrorData(res.data),
          total: this.getTotal(res.data),
        });
      } else if (res.data.status !== 1003) {
        if(this.counter > 100) {
          throw new Error(messages('common-1.key1299')/*导入超时，请重试*/);
        }
        this.delayer = setTimeout(() => this.listenStatus(transactionOID),  Math.min(1000 + this.counter * 3000, 30000));
        this.counter++;
      } else {
        onChange({
          errorData: this.getErrorData(res.data),
          total: this.getTotal(res.data),
          fileList: [],
          tabKey: 'RESULT',
          uploading: false,
          uploadResult: this.getUploadResult(res.data)
        })
      }
    }).catch(e => {
      this.counter = 0;
      onChange({ uploading: false });
      message.error(messages('common-1.key384')/*导入失败，请重试*/)
    })
  };

  //下载导入模板
  downloadTemplate = (template, index) => {
    const { downloadingList } = this.state;
    const { onDownloadTemplate,errorParser } = this.props.templateOptions;
    let { downFileExtension, downloadUrl, downFileName, templateName, downloadMethod, downloadParams } = template;
    let regObj = new RegExp(`^https?:\/\/.*\/.*\.${downFileExtension || 'xlsx'}$`);
    downloadingList[index] = true;
    this.setState({ downloadingList });
    message.loading(messages('common-1.key378')/*正在生成文件..*/);
    if(onDownloadTemplate) {
      onDownloadTemplate(template).then(() => {
        downloadingList[index] = false;
        this.setState({ downloadingList });
      }).catch(() => {
        downloadingList[index] = false;
        this.setState({ downloadingList });
        message.error(messages('common-1.key333')/*下载失败，请重试*/);
      })
    } else if(regObj.test(downloadUrl)) {
      window.location.href = downloadUrl;
      downloadingList[index] = false;
      this.setState({ downloadingList });
    } else {
      httpFetch[downloadMethod || 'get'](downloadUrl, downloadParams ? downloadParams : {}, {}, {responseType: 'arraybuffer'}).then(res => {
        let b = new Blob([res.data], {type: "file"});
        FileSaver.saveAs(b, `${downFileName || templateName}.${downFileExtension || 'xlsx'}`);
        downloadingList[index] = false;
        this.setState({ downloadingList });
      }).catch((e) => {
        let errorBody;
        downloadingList[index] = false;
        this.setState({ downloadingList });
        //因为axios请求参数设置了{responseType: 'arraybuffer'}，所以返回的错误信息是arraybuffer类型的，在这里做一个转换
        if(e && e.response && e.response.data instanceof ArrayBuffer){
          errorBody = JSON.parse(decodeUtf8(e.response.data));
        }
        message.error((errorParser && errorParser(errorBody || {})) || messages('common-1.key333')/*下载失败，请重试*/);
      })
    }

  };

  handleChangeInIE9 = (response) => {
    const { fileList } = this.state;
    const { onChange } = this.props;
    fileList.push(response);
    this.setState({ fileList }, () => {
      message.success(`${messages('common-1.key60')/*上传成功*/}`);
      onChange({fileList: this.state.fileList});
    });
  };

  beforeUpload = (file) => {
    const { fileList } = this.state;
    const { beforeUpload, onChange } = this.props;
    const { maxFileSize, accept } = this.uploadOptions;
    let fileObj = file;
    //组件设计中 其实是把上传这一步放到了模态框确认中, 所以这里默认不触发上传接口，能做的管控只有文件大小 文件数量，其余的默认添加成功
    if (maxFileSize) {  //文件的大小
      const isLtSize = file.size / 1024 / 1024 <= maxFileSize;
      if (!isLtSize) {
        this.uploadable = false;
        message.error(messages('common-1.key385',{arg1: maxFileSize})/*文件不能超过{arg1}M*/);
        return false;
      }
    }
    if(accept && fileObj.name) {
      //bugfix: 56475  accept只能限制到默认文件类型，用户还是可以手动修改为所有文件，这里由于业务组件都是上传Excel模板，通过文件名后缀管控一下
      let acceptExcel = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', '.xlsx', '.xls'];
      let acceptList = accept.split(',');
      let needControl = false;
      acceptList.map(i => acceptExcel.includes(i) && (needControl = true));
      if(needControl && !/.[xlsx|xls]$/.test(fileObj.name)) {
        this.uploadable = false;
        message.error(messages('common-1.key386')/*上传失败，文件格式错误！*/);
        return false;
      }
    }
    beforeUpload && (fileObj = beforeUpload(file));
    this.uploadable = true;
    this.setState({ fileList: [...fileList, fileObj] }, () => {
      onChange({fileList: this.state.fileList});
    });
    //默认不触发上传接口
    return false;
  };

  onRemove = (file) => {
    this.setState(({ fileList }) => {
      const index = fileList.indexOf(file);
      const newFileList = fileList.slice();
      newFileList.splice(index, 1);
      return {
        fileList: newFileList,
      };
    });
  };

  handleChange = (info) => {
    const { maxNum } = this.props.uploadOptions;
    let fileList = info.fileList;
    fileList = fileList.reverse().slice(-maxNum);
    if (info.file.status === 'error') {
      message.error(`${info.file.name ? info.file.name : ''}
      ${messages('common-1.key59')/*上传失败*/} ${info.file.response ? info.file.response.message : ''}`);
    }
    if( this.uploadable ) this.setState({ fileList });
  };

  renderInfoMessage = infoMessage => {
    if(typeof infoMessage === 'string')
      return (
        <Alert
          type="info"
          showIcon
          style={{marginBottom: 10}}
          message={infoMessage}
        />);
    else {
      return infoMessage;
    }
  };

  renderTemplateSection = templateOptions => {
    const { downloadingList } = this.state;
    const { templateTips, templateList, props } = templateOptions;
    return (
      <section className='left-template'>
        <h3 className='left-template-title'>{messages('common-1.key340')/*创建模板*/}</h3>
        <p>1.{messages('common-1.key387')/*下载所需模板*/}</p>
        <p>2.{messages('common-1.key388')/*严格按照导入模板整理数据，检查必输事项是否缺少数据*/}</p>
        <p>3.{messages('common-1.key389')/*关闭Excel文件后，方可进行数据导入*/}</p>
        {templateTips && <p>{templateTips}</p>}
        {templateList.map((template, index) => (
          <div className='left-template-list'>
            <Button
              key={`${index}`}
              icon="download"
              className='left-template-list-btn'
              loading={downloadingList[index]}
              onClick={() => this.downloadTemplate(template, index)}
              {...props}
            >
              {template.templateName || template.downFileName}
            </Button>
            {template.templateTips && <p className='left-template-tips'>{template.templateTips}</p>}
          </div>
        ))}
      </section>
    )
  };

  renderUploadSection = uploadOptions => {
    const { fileList } = this.state;
    const { authToken } = this.props;
    const { maxNum, uploadParams, uploadUrl, props, accept, maxFileSize, disabled } = uploadOptions;
    let tipsArr = { maxFileSize, maxNum };
    tipsArr = Object.keys(tipsArr).filter(i => !!tipsArr[i]).map(i => {
      if(i === 'maxFileSize') return messages('common-1.key390',{arg1: maxFileSize})/*文件不能大于{arg1}M*/;
      if(i === 'maxNum') return messages('common-1.key391',{arg1: maxNum})/*最多上传{arg1}个*/
    });
    return (
      <section className='right-uploader'>
        <h3 className='right-uploader-title'>{messages('common-1.key392')/*上传模板*/}</h3>
        <p>
          1. {messages('common-1.key393')/*点击【上传文件】按钮，选择更新过的模板文件*/}
          {`${tipsArr.length ? '(' + tipsArr.join(',') + ')' : ''}`}
        </p>
        {
          window.ISIE9 ?
            <FileUpload
              onChange={this.handleChangeInIE9}
              token={authToken.access_token}
              data={uploadParams}
              beforeUpload={this.beforeUpload}
              uploadUrl={uploadUrl}
              disabled={disabled || fileList.length >= maxNum}
              accept={accept}
              {...props}
            />
            :
            <Upload
              action={uploadUrl}
              headers={{
                Authorization: `Bearer ${authToken.access_token}`
              }}
              accept={accept}
              fileList={fileList}
              beforeUpload={this.beforeUpload}
              onRemove={this.onRemove}
              onChange={this.handleChange}
              disabled={disabled || fileList.length >= maxNum}
              {...props}
            >
              <Button disabled={disabled || fileList.length >= maxNum}>
                <Icon type="upload"/>
                {messages('common-1.key370')/*上传文件*/}
              </Button>
            </Upload>
        }
        <p className='right-uploader-tips-2'>
          2. {messages('common-1.key394')/*点击右下方【导入】，导入过程中请勿关闭对话框*/}
        </p>
      </section>
    )
  };

  render() {
    const { infoMessage, templateOptions, template } = this.props;
    return (
      <div className='importer-template'>
        { infoMessage && this.renderInfoMessage(infoMessage)  }
        <div className='importer-template-box'>
          { template ? template : templateOptions && this.renderTemplateSection(templateOptions) }
          { this.renderUploadSection(this.uploadOptions) }
        </div>
      </div>
    );
  }
}

UploadTemplate.propTypes = {
  asyncMode:  React.PropTypes.bool,  //是否是异步导入模式
  template: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.element]), //自定义左侧创建模板部分
  infoMessage: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.element]), //顶部提示文案
  templateOptions: React.PropTypes.oneOfType([React.PropTypes.bool, React.PropTypes.object]), //创建模板配置，为false不显示
  uploadOptions: React.PropTypes.object, //上传文件相关配置
  beforeUpload: React.PropTypes.func, //上传前文件格式化处理，详细见Upload组件
  afterUpload: React.PropTypes.func, //上传后结果回调
  onConfirmUpload: React.PropTypes.func, //上传失败需要确认继续上传的处理函数
  onChange: React.PropTypes.func, //内部参数，回调参数信息到父组件
  disabled: React.PropTypes.bool,  //禁用上传按钮
};

UploadTemplate.defaultProps = {
  asyncMode: false,
  disabled: false,
  infoMessage: '',
  templateOptions: {
    templateList: [{
      downloadUrl: '', //模板下载地址
      downFileName: '', //模板下载后文件名
      templateName: '', //模板显示文件名
      downFileExtension: 'xlsx' //模板后缀
    }],
    templateTips: '' //模板提示
  },
  uploadOptions: {
    maxNum: 1,
    uploadParams:{},
    uploadUrl: '/api/upload/attachment/v2',
    listenUrl: `${config.budgetUrl}/api/budget/batch/transaction/logs`,
    accept: 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    props: {}
  }
};

function mapStateToProps(state) {
  return {
    authToken: state.main.authToken
  }
}

export default connect(mapStateToProps)(UploadTemplate);
